import kid
import types

import blockarticle.doc as doc

WidgetList = ['BlockBase']

class NotSupport(Exception):
    """This class does not support this method."""
    pass

def Template(source = None, file = None, fragment=1, format='default'):
    """The decorator make the function return dict get and replace by Kid template."""
    def TemplateDecorator(Func):
        def NewFunc(*args, **kwargs):
            Result = Func(*args, **kwargs)
            if type(Result) is types.DictType:
                Template = kid.Template(source=source, file=file, **Result)
            else:
                return str(Result)
            return Template.serialize(fragment=fragment, output='xhtml-strict', format=format)
            
        return NewFunc
    return TemplateDecorator

class Renderable:
    """Renderable interface.
    
    Interface that want to be render on web, orvrride this object
    """
    
    def Render(self, DisplayEditable = False):
        """Render whole object
        
        If DisplayEditable is true, render editable option.
        """
        raise NotSupport
    
    def RenderContent(self, DisplayEditable = False):
        """Render content of this object.
        
        If DisplayEditable is true, render editable option.
        """
        raise NotSupport

    def RenderForm(self):
        """Render form for edit."""
        raise NotSupport
    
    @staticmethod
    def RenderHeader(DisplayEditable = False):
        """Render header
        
        @param DisplayEditable: Display editable or not 
        """
        raise NotSupport

class NodeBase(doc.Node, Renderable):
    
    FrameTemplate = """
    <div xmlns:py="http://purl.org/kid/ns#" id="node${ID}">
        <span py:if="DisplayEditable and not IsRoot" py:strip="True">
            <span id="insertform${ID}"></span>
            <div class="edit_bar">
                <a href="${InsertCommand}">Insert here</a>
                |
                <a href="${MoveCommand}">Move here</a>
                |
                <a href="${CopyCommand}">Copy here</a>                
            </div>
            <div class="edit_bar">
                <input type="radio" name="clip_radio" value="${ID}" /> 
                |
                <a href="${EditCommand}">Edit</a> 
                | 
                <a href="${DeleteCommand}">Delete</a>
            </div>
        </span>
        <span id="content${ID}">
            <span py:replace="XML(Content)">Content</span>
        </span>
    </div>
    """
    
    def getInsertCommand(self):
        return "javascript: LoadCommandResult('insertform', {'id': '%(ID)d', 'push_back': '0'});" % dict(ID = self.ID)
    
    def getMoveCommand(self):
        return "javascript: LoadCommandResult('move', {'id': GetCheckedRadioValue('clip_radio'), 'to': '%(ID)d', 'push_back': '0'});" % dict(ID = self.ID)
    
    def getCopyCommand(self):
        return "javascript: LoadCommandResult('copy', {'id': GetCheckedRadioValue('clip_radio'), 'to': '%(ID)d', 'push_back': '0'});" % dict(ID = self.ID)
    
    def getEditCommand(self):
        return  "javascript: LoadCommandResult('editform', {'id': '%(ID)d', 'tocallback_prefix': 'content'});" % dict(ID = self.ID)
    
    def getDeleteCommand(self):
        return  "javascript: DeleteConfirm('%(ID)d');" % dict(ID = self.ID)
    
    def __init__(self):
        doc.Node.__init__(self)
        
    @Template(source = FrameTemplate)
    def Render(self, DisplayEditable = False):       
        Dictionary = {}
        Dictionary['DisplayEditable'] = DisplayEditable
        Dictionary['IsRoot'] = (self.Parent == None)
        Dictionary['ID'] = self.ID
        Dictionary['Content'] = self.RenderContent(DisplayEditable)
        Dictionary['InsertCommand'] = self.getInsertCommand()
        Dictionary['MoveCommand'] = self.getMoveCommand()
        Dictionary['CopyCommand'] = self.getCopyCommand()
        Dictionary['EditCommand'] = self.getEditCommand()
        Dictionary['DeleteCommand'] = self.getDeleteCommand()
        return Dictionary
        
    @staticmethod
    def RenderHeader(DisplayEditable = False):
        return ''

class BlockBase(doc.Block, NodeBase):
    ContentTemplate = """
    <div xmlns:py="http://purl.org/kid/ns#" class="block_base">
        <span py:for="Child in Children" py:replace="XML(Child.Render(DisplayEditable))"></span>
        <span id="pushbackform${ID}"></span>
        <div py:if="DisplayEditable" class="edit_bar">
            <a href="javascript: LoadCommandResult('insertform', {'id': '${ID}', 'push_back': '1'});">Push back here</a>
            |
            <a href="javascript: LoadCommandResult('move', {'id': GetCheckedRadioValue('clip_radio'), 'to': '${ID}', 'push_back': '1'});">Move here</a>
            |
            <a href="javascript: LoadCommandResult('copy', {'id': GetCheckedRadioValue('clip_radio'), 'to': '${ID}', 'push_back': '1'});">Copy here</a>
        </div>
    </div>
    """
    
    def __init__(self):
        NodeBase.__init__(self)
        doc.Block.__init__(self)

    @Template(source = ContentTemplate)
    def RenderContent(self, DisplayEditable = False):
        return dict(ID = self.ID, Children = self.Children, DisplayEditable = DisplayEditable)

    def RenderForm(self):
        return self.RenderContent(DisplayEditable = True)

if __name__ == '__main__':
    MyDoc = doc.Doc(StdBlock)
    
    MyDoc.Root.PushBack(TestWidget())
    MyDoc.Root.PushBack(StdBlock())
    MyDoc.Root.PushBack(TestWidget())
    
    MyDoc.GetChild('1').PushBack(TestWidget())
    MyDoc.GetChild('1').PushBack(StdBlock())
    MyDoc.GetChild('1').PushBack(StdBlock())
    MyDoc.GetChild('1').PushBack(StdBlock())
    
    print MyDoc.Root
    print MyDoc.Root.Render()